import pygame
import  typing
import weakref
from timer import Timer
from signal_slot import Signal
from collision_shape import *



class Area:
    """
    使用CollisionShape设定一个区域，能够检测到sprite的进入和退出。
    # Note: 确保该类检测的"pygame.sprite.Sprite"对象有"collision_rect"属性
    """

    def __init__(self, shape: CollisionShape) -> None:
        self.__cls_shape: CollisionShape = shape
        self.__pos: pygame.Vector2 = self.__cls_shape.pos
        self.__entered_obj_refs: list[weakref.ReferenceType] = []
        self.__show_shape: bool = False

        self.sprite_entered_signal = Signal()
        self.sprite_exited_signal = Signal()

    def update(self, sprites: CollidableObjs, *args, **kwargs) -> None:
        sprites = sprites.sprites() if isinstance(sprites, pygame.sprite.Group) else sprites
        # sprite enter
        for sprite in sprites:
            entered = False
            for ref in self.__entered_obj_refs:
                if ref() == sprite:
                    entered = True
                    break
            if not entered and self.__cls_shape.collide(sprite):
                self.__entered_obj_refs.append(weakref.ref(sprite))
                self.sprite_entered_signal.emit(sprite)
        # sprite exit
        temp_refs = []
        for ref in self.__entered_obj_refs:
            if not self.__cls_shape.collide(ref()):
                self.sprite_exited_signal.emit(ref())
                temp_refs.append(ref)
        for ref in temp_refs:
            self.__entered_obj_refs.remove(ref)

    def draw(self, surface: pygame.Surface, *args, **kwargs) -> None:
        if not self.__show_shape:
            return
        self.__cls_shape.draw(surface, *args, **kwargs)

    def get_pos(self) -> pygame.Vector2:
        return self.__pos
    
    def set_pos(self, value: pygame.Vector2) -> "Area":
        self.__pos = value
        self.__cls_shape.pos = self.__pos
        return self
    
    def is_show_shape(self) -> bool:
        return self.__show_shape
    
    def show_shape(self, value: bool) -> "Area":
        self.__show_shape = value
        return self

    def get_shape_color(self) ->  pygame.Color:
        return self.__cls_shape.draw_color
    
    def set_shape_color(self, color: pygame.Color) -> "Area":
        self.__cls_shape.draw_color = color
        return self